;*****************************************************************************************************
;+
; NAME:
;
;      eLEGEND (enhanced LEGEND)
;
; PURPOSE:
;
;      This routine draws a legend on the current established
;      axis coordinate system. The legend consists of items where each
;      item is a line/symbol + a text. An optional box can be drawn
;      around the legend and a background color can be specified.
;
; CALLING SEQUENCE:
;
;      eLEGEND, labels
;
; ARGUMENTS:
;
;     LABELS:       Scalar or vector of strings specifying the labels
;                   for each legend item. If this is not specified,
;                   the routine will try to find the number Ntot of line
;                   plots in the current graphic and use the
;                   labels 'Plot N' where N ranges from 1 to Ntot.
;                 
; KEYWORD PARAMETERS:
;
;     BOX:          Flag indicating if a box is drawn around the
;                   legend. The default is 1 (the box is drawn).
;
;     BACKGROUND:   Set this keyword to fill the legend with
;                   the background color specified by BGCOLOR. This
;                   automatically sets BOX = 1 so if you don't
;                   want to draw the box lines, set BOXCOLOR to the
;                   same color as BGCOLOR.
;
;     BGCOLOR:      The name of the background color for the box. The
;                   default is !IGL_P.background
;
;     BOXCOLOR:     The name of the foreground color for the box. The
;                   default is !IGL_P.color
;
;     BOXLINESTYLE: The line style for the box. The default is !IGL_P.linestyle
;
;     BOXTHICKNESS: The line thickness for the box. The default is !IGL_P.thick
;
;     HORIZONTAL:   Set this keyword to produce a legend with a
;                   horizontal layout. The default is to have a
;                   vertical layout.
;
;     HSPACE:       Scalar specifying the horizontal space between
;                   each legend item in normalized coordinates. The
;                   default is 0.02.
;
;     VSPACE:       Scalar specifying the vertical space between
;                   each legend item in normalized coordinates. The
;                   default is 0.02.
;
;     HSIZE:        A scalar or vector specifying the horizontal size
;                   in normalized coordinates of the space occupied by
;                   the line/symbol. If a vector, should have the same
;                   number of elements as LABELS. Set this to 0 to
;                   prevent line or symbols from being drawn (only
;                   labels will be visible). A default of 0.1 is
;                   used.
;
;     CHARSIZE:     The character size for the labels (float). The default
;                   is !IGL_P.charsize
;
;     CHARTHICK:    The character thickness for the labels (integer). The
;                   default is !IGL_P.charthick
;
;     COLOR:        Scalar or vector of color names specifying the
;                   color for each legend item. If a vector, should
;                   have the same number of elements as LABELS.
;
;     FONT:         The character font for the labels (integer).
;                   -1 : Herschey, 0 : Hardware, 1 : True Type. The
;                   default is !IGL_P.font
;
;     LINESTYLE:    Scalar of vector of line style for each legend item. If a vector,
;                   should have the same number of elements as
;                   LABELS. If both LINESTYLE and PSYM are not
;                   specified, the line style and symbols of each plot
;                   in the current graphic is used. 
;
;     NODRAW:       Set this keyword to prevent the
;                   current window to be refreshed. The legend
;                   is added to the window but will not be
;                   visible until the window is refreshed (by calling
;                   another IGL plotting command for example). This is
;                   useful is you wish to issue several plotting
;                   commands but want to display the results only at
;                   the end.
;
;     ORDER:        Set this keyword if you want that each legend item
;                   have the text in front of the line/symbol.
;
;     ORIENTATION:  Specify the counterclockwise angle in degrees from the
;                   horizontal to draw the labels. The default is 0.0
;
;     PSYM:         Scalar or vector of symbols for each legend
;                   item. If a vector, should have the same number of elements as
;                   LABELS. If both LINESTYLE and PSYM are not
;                   specified, the line style and symbols of each plot
;                   in the current graphic is used.
;
;     SYMSIZE:      Scalar or vector of symbol sizes for each legend
;                   item. If a vector, should have the same number of elements as
;                   LABELS.
;
;     SPACE:        A scalar or vector specifying the space between
;                   the line/symbol and the text of each item in
;                   normalized coordinates. If a vector, should have the same
;                   number of elements as LABELS. A default of 0.02 is
;                   used.
;
;     TEXTCOLOR:    The name of the color for the labels. The default
;                   is !IGL_P.color
;
;     THICK:        Scalar or vector of line thicknesses for each legend
;                   item. If a vector, should have the same number of elements as
;                   LABELS. If not provided, the thickness of each
;                   plot in the current graphic is used.
;
;     TOP:          Set this keyword to place the legend at the top of
;                   the graphic. This is the default.
;
;     BOTTOM:       Set this keyword to place the legend at the bottom
;                   of the graphic.
;
;     LEFT:         Set this keyword to place the legend at the left
;                   of the graphic. This is the default.
;
;     RIGHT:        Set this keyword to place the legend at the right
;                   of the graphic. 
;
;    
; PACKAGE:
;
;    Interactive Graphics Library (IGL)
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
;
; MODIFICATION HISTORY:
;
;     Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
PRO eLEGEND, labels, $
             BACKGROUND=background, $
             BOX=box, $
             BGCOLOR=bgcolor, $
             BOXCOLOR=boxcolor, $
             BOXLINESTYLE=boxlinestyle, $
             BOXTHICKNESS=boxthickness, $
             FONT=font, $
             CHARSIZE=charsize, $
             CHARTHICK=charthick, $
             ORIENTATION=orientation, $
             TEXTCOLOR=textcolor, $
             HORIZONTAL=horizontal, $
             HSPACE=hspace, $
             VSPACE=vspace, $
             COLOR=color, $
             LINESTYLE=linestyle, $
             THICK=thick, $
             PSYM=psym, $
             SYMSIZE=symsize, $
             TOP=top, $
             BOTTOM=bottom, $
             LEFT=left, $
             RIGHT=right, $
             SPACE=space, $
             HSIZE=hsize, $
             NODRAW=nodraw
  
  COMPILE_OPT idl2, HIDDEN
  ON_ERROR, 2

  ;; Initialize the global system variables
  IGL_InitSysVars

  ;; Default keyword values
  IF N_Elements(bgcolor) EQ 0 THEN bgcolor = !IGL_P.background
  IF N_Elements(boxcolor) EQ 0 THEN boxcolor = !IGL_P.color
  IF N_Elements(boxlinestyle) EQ 0 THEN boxlinestyle = !IGL_P.linestyle
  IF N_Elements(boxthickness) EQ 0 THEN boxthickness = (!IGL_P.thick LE 0) ? 1: !IGL_P.thick
  IF N_Elements(font) EQ 0 THEN font = !IGL_P.font
  IF N_Elements(charsize) EQ 0 THEN charsize = (!IGL_P.charsize LE 0) ? 1 : !IGL_P.charsize
  IF N_Elements(charthick) EQ 0 THEN charthick = (!IGL_P.charthick LE 0) ? 1 : !IGL_P.charthick
  IF N_Elements(orientation) EQ 0 THEN orientation = 0.0
  IF N_Elements(textcolor) EQ 0 THEN textcolor = !IGL_P.color

  ;; Get current window
  currentWindow = IGL_GetCurrentWindow()
  IF OBJ_ISA_VALID(currentWindow,'IGL_Window') EQ 0 THEN Message, 'No valid IGL window available'
  currentWindow -> GetProperty, Window_Xsize=Xsize, Window_Ysize=Ysize

  ;; Get the current coordinate system
  currentCoords = IGL_GetSysVars('currentCoord')
  IF OBJ_ISA_VALID(currentCoords,'CatCoord') EQ 0 THEN Message, 'A coordinate system is not established'
  
  ;; Get the object that represents the coordinate system in the graphic
  currentCoords -> GetProperty, FIRST_PARENT=parent
  IF OBJ_VALID(parent) EQ 0 THEN Message, 'Invalid coordinate system'
  
  ;; Get the graphic in which the parent object is contained
  parent -> GetProperty, FIRST_PARENT=graphic
  IF OBJ_ISA_VALID(graphic,'IGL_Graphic') EQ 0 THEN message, 'Current coordinate system is not in a valid graphic'

  ;; Get the graphic coordinate system
  graphic -> GetProperty, Coord_Object=graphicCoords

  ;; Do we need to draw the box ?
  IF Keyword_Set(box) OR (N_Elements(box) EQ 0) THEN drawBox = 1
  IF Keyword_Set(background) THEN drawBox = 1

  ;; Get the line plots in the current graphic
  plotObjects = graphic -> Get(/ALL,ISA='IGL_Plot',/Recursive_Search,Count=count)
  
  ;; Check if the user provided the labels. If not, use as many labels
  ;; as we can find line plots in the current graphic.
  IF N_Elements(labels) EQ 0 THEN BEGIN
     IF count EQ 0 THEN Message, "Couldn't find any plot to legend" $
     ELSE labels = 'Plot '+StrTrim(lindgen(count)+1,2)
  ENDIF
  nLabels = N_Elements(labels)


  ;; Default colors
  IF N_Elements(color) EQ 0 THEN BEGIN
     
     IF count EQ 0 THEN color = Replicate(!IGL_P.color,nLabels) $                                    
     ELSE BEGIN
        color = strarr(count)
        FOR i=0, count-1 DO BEGIN
           plotObjects[i] -> GetProperty, Color=cl
           color[i] = cl
        ENDFOR
     ENDELSE
     
  ENDIF
  nColor = N_Elements(color)
  IF nColor GT 1 THEN IF nColor NE nLabels THEN Message, 'Color and Labels must have same number of elements'

  ;; Default linestyles
  IF N_Elements(linestyle) EQ 0 THEN BEGIN
     
     IF count EQ 0 THEN linestyle = Replicate(!IGL_P.linestyle,nLabels) $                                    
     ELSE BEGIN
        linestyle = intarr(count)
        FOR i=0, count-1 DO BEGIN
           plotObjects[i] -> GetProperty, Linestyle=ls
           linestyle[i] = ls
        ENDFOR
     ENDELSE
     
  ENDIF
  nLineStyle = N_Elements(linestyle)
  IF nLineStyle GT 1 THEN IF nLineStyle NE nLabels THEN Message, 'Linestyle and Labels must have same number of elements'

  ;; Default line thicknesses
  IF N_Elements(thick) EQ 0 THEN BEGIN
     
     IF count EQ 0 THEN BEGIN
        value = (!IGL_P.thick LE 0) ? 1 : !IGL_P.thick
        thick = Replicate(value,nLabels)
     ENDIF ELSE BEGIN
        thick = intarr(count)
        FOR i=0, count-1 DO BEGIN
           plotObjects[i] -> GetProperty, Thick=th
           thick[i] = th
        ENDFOR
     ENDELSE
     
  ENDIF
  nThick = N_Elements(thick)
  IF nThick GT 1 THEN IF nThick NE nLabels THEN Message, 'Thick and Labels must have same number of elements'

  ;; Default symbols
  IF N_Elements(psym) EQ 0 THEN BEGIN
     
     IF count EQ 0 THEN psym = Replicate(!IGL_P.psym,nLabels) $
     ELSE BEGIN
        psym = intarr(count)
        FOR i=0, count-1 DO BEGIN
           plotObjects[i] -> GetProperty, Psym=ps
           psym[i] = ps
        ENDFOR
     ENDELSE
  ENDIF  
  nPsym = N_Elements(psym)
  IF nPsym GT 1 THEN IF nPsym NE nLabels THEN Message, 'Psym and Labels must have same number of elements'

  ;; Default symbol sizes
  IF N_Elements(symsize) EQ 0 THEN BEGIN
     
     IF count EQ 0 THEN BEGIN
        value = (!IGL_P.symsize LE 0) ? 1 : !IGL_P.symsize
        symsize = Replicate(value,nLabels)
     ENDIF ELSE BEGIN
        symsize = fltarr(count)
        FOR i=0, count-1 DO BEGIN
           plotObjects[i] -> GetProperty, SymSize=ss
           symsize[i] = ss
        ENDFOR
     ENDELSE
     
  ENDIF
  nSymsize = N_Elements(symsize)
  IF nSymsize GT 1 THEN IF nSymsize NE nLabels THEN Message, 'Symsize and Labels must have same number of elements'

  ;; Create the legend object
  legend = Obj_New('IGL_Legend', $
                   BACKGROUND=Keyword_Set(background), $
                   DRAWBOX=Keyword_Set(drawBox), $
                   BGCOLOR=bgcolor, $
                   BOXCOLOR=boxcolor, $
                   LINESTYLE=boxlinestyle, $
                   THICKNESS=boxthickness, $
                   VSPACE=vspace, $
                   HSPACE=hspace, $
                   HORIZONTAL=Keyword_Set(horizontal), $
                   COORD_OBJECT=graphicCoords $
                  )

  ;; Create the legend items
  FOR i=0, nLabels-1 DO BEGIN

     IF nColor GT 1 THEN cl = color[i] ELSE cl = color[0]
     IF nLineStyle GT 1 THEN ls = linestyle[i] ELSE ls = linestyle[0]
     IF nThick GT 1 THEN th = thick[i] ELSE th = thick[0]
     IF nPsym GT 1 THEN ps = psym[i] ELSE ps = psym[0]
     IF nSymsize GT 1 THEN ss = symsize[i] ELSE ss = symsize[0]

     item = obj_new('IGL_LegendItem', $
                    TEXT=labels[i], $
                    PCOLOR=cl, $
                    LINESTYLE=ls, $
                    PSYM=ps, $
                    SYMSIZE=ss, $
                    THICK=th, $
                    CHARSIZE=charsize, $
                    CHARTHICK=charthick, $
                    FONT=(font+1), $
                    ORIENTATION=orientation, $
                    TCOLOR=textcolor, $
                    ORDER=Keyword_Set(order), $
                    HSIZE=hsize, $
                    SPACE=space $
                    )
     

     ;; Add the item to the legend object
     legend -> Add, item

  ENDFOR

  ;; Position the legend in the graphic

  ;; First we calculate the height and width of the legend
  legend -> CalculateBoundaryBox
  legend -> GetProperty, BoxObject=boxObject
  boxObject -> GetProperty, Xpts=xpts, Ypts=ypts
  height = ypts[1]-ypts[0]
  width = xpts[2]-xpts[0]

  ;; Now we assign the position based on the positioning keywords
  IF Keyword_Set(bottom) THEN ypos = 0.1+height
  IF Keyword_Set(top) OR (N_Elements(ypos) EQ 0) THEN ypos = 0.9
  IF Keyword_Set(right) THEN xpos = 0.9-width
  IF Keyword_Set(left) OR (N_Elements(xpos) EQ 0) THEN xpos = 0.1
  legend -> SetProperty, Xpos=xpos, Ypos=ypos

  ;; Add the legend to the graphic
  graphic -> Add, legend

  ;; Refresh property editor
  currentWindow -> GetProperty, PropertyPanel=PropertyPanel
  IF OBJ_VALID(PropertyPanel) THEN PropertyPanel -> UpdateTreeBrowser
 
  ;; Draw window's content
  IF Keyword_Set(nodraw) EQ 0 THEN currentWindow -> DrawWindow, /BUFFERED_OUTPUT


END
